/*
 * @(#)ReverseSectionsOperator.java 1.0 15/11/13
 *
 */

package dominio;

import java.util.ArrayList;
import java.util.Collections;

/**
 * Created by Rafael Simon Garcia on 11/15/13.
 */

public class ReverseSectionsOperator extends HillClimbingOperator{
    private static PermutationsIterator coordinatesPermutations;
    private static int length; //length of a tour


    //constructor with the length of a tour
    public static void InitializeOperator(int l){
        length = l;
        coordinatesPermutations = new PermutationsIterator(length);
    }

    //returns the result of operating on the tour received as an input argument
    public static ArrayList<Integer> Operate(ArrayList<Integer> currentPath){
        if(coordinatesPermutations == null) InitializeOperator(currentPath.size());

        ArrayList<Integer> nextPath = new ArrayList<>();

        //if there is a next value on the iterator
        if(coordinatesPermutations.HasNextValue()){
            //get that next value
            ValuesPair p = coordinatesPermutations.NextValue();
            int start= p.first, end = p.second;

            if(start != end){ //if the values from the pair are different
                nextPath = new ArrayList<>(currentPath); //copy the input tour into a new ArrayList
                if(start < end)
                    ReverseWhenStartLessThanEnd(nextPath, start, end); //reverse it when start is less than end

                else
                    ReverseWhenStartMoreThanEnd(nextPath, start, end); //reverse it when end is less than start
            }
        }
        return nextPath;
    }

    private static void ReverseWhenStartLessThanEnd(ArrayList<Integer> currentPath, int start, int end){
        Collections.reverse(currentPath.subList(start, end + 1));
    }


    private static void ReverseWhenStartMoreThanEnd(ArrayList<Integer> currentPath, int start, int end){
        ArrayList<Integer> slice1, slice2, slice3;
        //splits the original tour in 3 slices
        slice1 = new ArrayList<>(currentPath.subList(0, end));
        slice2 = new ArrayList<>(currentPath.subList(start + 1, length));
        slice3 = new ArrayList<>(currentPath.subList(end, start + 1));

        //reverses slices 1 and 2
        Collections.reverse(slice1);
        Collections.reverse(slice2);

        currentPath.clear();
        //puts the end slice at the start, then the middle slice unreversed then the start slice at the end
        currentPath.addAll(slice2);
        currentPath.addAll(slice3);
        currentPath.addAll(slice1);
    }

    //returns whether there's a next value available on the operator.
    public static boolean HasNextValue(){
        return coordinatesPermutations.HasNextValue();
    }

    //resets the operator by resetting the permutations iterator.
    public static void Reset(){
        coordinatesPermutations.Reset();
    }
}
